import { MixpanelLogo } from "@/src/components/MixpanelLogo"; import Header from "@/src/components/layouts/header"; import ContainerPage from "@/src/components/layouts/container-page"; import { StatusBadge } from "@/src/components/layouts/status-badge"; import { Button } from "@/src/components/ui/button"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/src/components/ui/form"; import { PasswordInput } from "@/src/components/ui/password-input"; import { Switch } from "@/src/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/src/components/ui/select"; import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture"; import { mixpanelIntegrationFormSchema, MIXPANEL_REGIONS, type MixpanelRegion, } from "@/src/features/mixpanel-integration/types"; import { useHasProjectAccess } from "@/src/features/rbac/utils/checkProjectAccess"; import { api } from "@/src/utils/api"; import { type RouterOutput } from "@/src/utils/types"; import { zodResolver } from "@hookform/resolvers/zod"; import { Card } from "@tremor/react"; import Link from "next/link"; import { useRouter } from "next/router"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { type z } from "zod/v4"; export default function MixpanelIntegrationSettings() { const router = useRouter(); const projectId = router.query.projectId as string; const hasAccess = useHasProjectAccess({ projectId, scope: "integrations:CRUD", }); const state = api.mixpanelIntegration.get.useQuery( { projectId }, { enabled: hasAccess, }, ); const status = state.isInitialLoading || !hasAccess ? undefined : state.data?.enabled ? "active" : "inactive"; return ( {status && }, actionButtonsRight: ( ), }} >

Integrate with{" "} Mixpanel {" "} to sync your Langfuse traces, generations, and scores for advanced product analytics. Upon activation, all historical data from your project will be synced. After the initial sync, new data is automatically synced every hour to keep your Mixpanel dashboards up to date.

{!hasAccess && (

Your current role does not grant you access to these settings, please reach out to your project admin or owner.

)} {hasAccess && ( <>
)} {state.data?.enabled && ( <>

Data synced until:{" "} {state.data?.lastSyncAt ? new Date(state.data.lastSyncAt).toLocaleString() : "Never (pending)"}

)} ); } const MixpanelIntegrationSettingsForm = ({ state, projectId, isLoading, }: { state?: RouterOutput["mixpanelIntegration"]["get"]; projectId: string; isLoading: boolean; }) => { const capture = usePostHogClientCapture(); const mixpanelForm = useForm({ resolver: zodResolver(mixpanelIntegrationFormSchema), defaultValues: { mixpanelRegion: (state?.mixpanelRegion as MixpanelRegion) ?? MIXPANEL_REGIONS[0].subdomain, mixpanelProjectToken: state?.mixpanelProjectToken ?? "", enabled: state?.enabled ?? false, }, disabled: isLoading, }); useEffect(() => { mixpanelForm.reset({ mixpanelRegion: (state?.mixpanelRegion as MixpanelRegion) ?? MIXPANEL_REGIONS[0].subdomain, mixpanelProjectToken: state?.mixpanelProjectToken ?? "", enabled: state?.enabled ?? false, }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [state]); const utils = api.useUtils(); const mut = api.mixpanelIntegration.update.useMutation({ onSuccess: () => { utils.mixpanelIntegration.invalidate(); }, }); const mutDelete = api.mixpanelIntegration.delete.useMutation({ onSuccess: () => { utils.mixpanelIntegration.invalidate(); }, }); async function onSubmit( values: z.infer, ) { capture("integrations:mixpanel_form_submitted"); mut.mutate({ projectId, ...values, }); } return (
( Mixpanel Region Select the Mixpanel region where your project is hosted )} /> ( Mixpanel Project Token You can find your Project Token in your Mixpanel project settings )} /> ( Enabled { field.onChange(!field.value); }} className="ml-4 mt-1" /> )} />
); };